﻿using System;
using System.Collections.Generic;
using System.Text;

namespace DbfDotNet.Core
{
    internal sealed class DbtFile : ClusteredFile
    {
        protected static QuickSerializer mDbtHeaderWriter;
        protected static QuickSerializer mDbtPageWriter;
        DbtHeader mDbtHeader;
        internal DbfFile mDbfFile;

        public DbtFile()
        {
        }

        static DbtFile()
        {
            mDbtHeaderWriter = new QuickSerializer(typeof(DbtHeader), DbfVersion.DbfDotNet, null, 0,
                /*ignoremissingfields*/ false, true);
            mDbtPageWriter = new QuickSerializer(typeof(DbtPage), DbfVersion.DbfDotNet, null, 0,
                /*ignoremissingfields*/ false, true);
        }

        protected override void OnInitialize(System.IO.Stream stream)
        {
            Byte[] headerBuff = new byte[mDbtHeaderWriter.RecordWidth];
            mDbtHeader = new DbtHeader();
            int read = stream.Read(headerBuff, 0, headerBuff.Length);

            if (read > 0)
            {
                mDbtHeaderWriter.Read(mDbfFile, headerBuff, mDbtHeader);
                mRecordWidth=mDbtHeader.BlockLength;
                if (mRecordWidth == 0 || mDbtHeader.NdtVersion == 3) mRecordWidth = 512;
                mHeaderWidth = mRecordWidth;
            }
        }

        protected override Record OnCreateNewRecord(bool isNew, uint recordNo)
        {
            return new DbtPage();
        }

        protected override void OnWriteHeader(System.IO.Stream stream)
        {
            throw new NotImplementedException();
        }

        protected override void OnReadRecordBuffer(byte[] buffer, Record record)
        {
            var dbtPage = (DbtPage)record;
            System.IO.MemoryStream result;
            if (mDbtHeader.NdtVersion == 3)
            {
                result = new System.IO.MemoryStream();
                bool seenTerminator = false;
                while (seenTerminator==false)
                {
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        if (buffer[i] == 0x1A)
                        {
                            if (i > 0) result.Write(buffer, 0, i);
                            seenTerminator = true;
                            break;
                        }
                    }
                    if (seenTerminator) break;
                    result.Write(buffer, 0, buffer.Length);

                    if (!base.ReadNextPage(buffer))
                    {
                        System.Diagnostics.Debug.Assert(false, "We haven't seen the Terminator");
                        break;
                    }
                }
                dbtPage.Value = result.ToArray();
            }
            else
            {
                mDbtPageWriter.Read(mDbfFile, buffer, dbtPage);
                result = new System.IO.MemoryStream();
                if (dbtPage.Length<=buffer.Length-8)
                {
                    result.Write(buffer,8,(Int32)dbtPage.Length);
                }
                else
                {
                    result.Write(buffer, 8, buffer.Length - 8);
                    buffer = new Byte[dbtPage.Length - result.Length];
                    base.ReadNextPage(buffer);
                }
            }
            dbtPage.Value=result.ToArray();
        }

        internal override bool OnFillWriteBuffer(Record record, byte[] buffer)
        {
            //throw new NotImplementedException();
            return false;
        }

        protected internal override Record InternalGetRecord(uint recordNo, bool returnNullIfNotInCache)
        {
            return base.InternalGetRecord(recordNo, returnNullIfNotInCache);
        }

        public override void Flush()
        {
            base.Flush();
        }

        public override object NewRecord()
        {
            return base.NewRecord();
        }

        internal override void OnWriteBufferModified(uint recordNo, byte[] oldBuffer, byte[] newBuffer)
        {
            base.OnWriteBufferModified(recordNo, oldBuffer, newBuffer);
        }

        internal byte[] GetMemoValue(uint memoRecordNo)
        {
            DbtPage page = (DbtPage)InternalGetRecord(memoRecordNo - 1,/*return null*/false);
            return page.Value;
        }
    }
}
